/**
  ******************************************************************************
  * @file    SRAM_Driver.c
  * @author  tuancheng_Zero
  * @version V0.1
  * @date    08/05/2024
  * @brief   extern Sram Drive
  ******************************************************************************
*/ 
#include <includes.h>
#include "SRAM_Driver.h"

//局部宏定义
#define SRAM_CS_LOW()         GPIO_ResetBits(SRAM_GPIOx, SRAM_GPIO_Pin_CS)   //使能
#define SRAM_CS_HIGH()        GPIO_SetBits(SRAM_GPIOx, SRAM_GPIO_Pin_CS)     //失能
#define SRAM_ADDR_SIZE_MAX    0x800000                                       //SRAM的大小8MB

//函数声明
void SRAM_GpioInit(void);
void SRAM_SpiInit(void);
void SRAM_DmaInit(void);
void SRAM_NvicInit(void);

//全局变量
uint8_t SRAM_DmaTX_Buff[SRAM_DMA_BUFF_SIZE] = {0};
uint8_t SRAM_DmaRX_Buff[SRAM_DMA_BUFF_SIZE] = {0};

/// @brief 外部扩展SRAM初始化
/// @param  none
void SRAM_Init(void){
    //打开外设时钟
    RCC_EnableAPB2PeriphClk(SRAM_GPIO_RCC_Periph | RCC_APB2_PERIPH_AFIO | RCC_APB2_PERIPH_SPI1, ENABLE);
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
    //SPI1引脚重映射
    GPIO_ConfigPinRemap(GPIO_RMP3_SPI1, ENABLE);
    //初始化GPIO
    SRAM_GpioInit();
    //初始化SPI
    SRAM_SpiInit();
    //初始化DMA
    SRAM_DmaInit();
    //初始化NVIC
    SRAM_NvicInit();
}

/// @brief Gpio引脚初始化
/// @param  none
void SRAM_GpioInit(void){
    GPIO_InitType GPIO_InitStructure;
    //初始化GPIO引脚
    GPIO_InitStructure.GPIO_Mode = SRAM_GPIO_Mode_MOSI;
    GPIO_InitStructure.Pin = SRAM_GPIO_Pin_MOSI;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitPeripheral(SRAM_GPIOx, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = SRAM_GPIO_Mode_MISO;
    GPIO_InitStructure.Pin = SRAM_GPIO_Pin_MISO;
    GPIO_InitPeripheral(SRAM_GPIOx, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = SRAM_GPIO_Mode_SCK;
    GPIO_InitStructure.Pin = SRAM_GPIO_Pin_SCK;
    GPIO_InitPeripheral(SRAM_GPIOx, &GPIO_InitStructure);
    GPIO_InitStructure.GPIO_Mode = SRAM_GPIO_Mode_CS;
    GPIO_InitStructure.Pin = SRAM_GPIO_Pin_CS;
    GPIO_InitPeripheral(SRAM_GPIOx, &GPIO_InitStructure);

    //引脚电平初始化
    SRAM_CS_HIGH();
}

/// @brief SPI外设初始化
/// @param  none
void SRAM_SpiInit(void){
    SPI_InitType SPI_InitStructure;
    //SPI配置
    SPI_InitStructure.DataDirection = SRAM_Direction;
    SPI_InitStructure.SpiMode = SRAM_Mode;
    SPI_InitStructure.DataLen = SRAM_DataSize;
    SPI_InitStructure.CLKPOL = SRAM_CPOL;
    SPI_InitStructure.CLKPHA = SRAM_CPHA;
    SPI_InitStructure.NSS = SRAM_NSS;
    SPI_InitStructure.BaudRatePres = SRAM_BaudRatePres;
    SPI_InitStructure.FirstBit = SRAM_FirstBit;
    SPI_InitStructure.CRCPoly = SRAM_CRCPoly;
    SPI_Init(SRAM_SPI, &SPI_InitStructure);
    //打开SPI
    SPI_Enable(SRAM_SPI, ENABLE);
}

/// @brief DMA外设初始化
/// @param  none
void SRAM_DmaInit(void){
    DMA_InitType DMA_InitStructure;
    //dma发送初始化
    DMA_DeInit(SRAM_DMA_Tx_Channel);
    DMA_InitStructure.PeriphAddr = SRAM_DR_Address;
    DMA_InitStructure.MemAddr = (uint32_t)SRAM_DmaTX_Buff;
    DMA_InitStructure.Direction = DMA_DIR_PERIPH_DST;
    DMA_InitStructure.BufSize = 0;
    DMA_InitStructure.PeriphInc = DMA_PERIPH_INC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc = DMA_MEM_INC_ENABLE;
    DMA_InitStructure.PeriphDataSize = DMA_PERIPH_DATA_SIZE_BYTE;
    DMA_InitStructure.MemDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.CircularMode = DMA_MODE_NORMAL;
    DMA_InitStructure.Priority = DMA_PRIORITY_VERY_HIGH;
    DMA_InitStructure.Mem2Mem = DMA_M2M_DISABLE;
    DMA_Init(SRAM_DMA_Tx_Channel, &DMA_InitStructure);
    SPI_I2S_EnableDma(SRAM_SPI, SPI_I2S_DMA_TX, ENABLE);
    DMA_EnableChannel(SRAM_DMA_Tx_Channel, DISABLE);
    //dma接收初始化
    DMA_DeInit(SRAM_DMA_Rx_Channel);
    DMA_InitStructure.PeriphAddr = SRAM_DR_Address;
    DMA_InitStructure.MemAddr = (uint32_t)SRAM_DmaRX_Buff;
    DMA_InitStructure.Direction = DMA_DIR_PERIPH_SRC;
    DMA_InitStructure.BufSize = sizeof(SRAM_DmaRX_Buff);
    DMA_Init(SRAM_DMA_Rx_Channel, &DMA_InitStructure);
    DMA_ConfigInt(SRAM_DMA_Rx_Channel, DMA_INT_TXC, ENABLE);
    DMA_ConfigInt(SRAM_DMA_Rx_Channel, DMA_INT_ERR, ENABLE);
    SPI_I2S_EnableDma(SRAM_SPI, SPI_I2S_DMA_RX, ENABLE);
    DMA_EnableChannel(SRAM_DMA_Rx_Channel, DISABLE);
    
}

/// @brief 嵌套中断初始化
/// @param  none
void SRAM_NvicInit(void){
    NVIC_InitType NVIC_InitStructure;
    //打开dma接收中断
    NVIC_InitStructure.NVIC_IRQChannel = SRAM_DMA_Rx_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/// @brief DMA数据传输
/// @param addr 传输地址
/// @param writeData 需要写入的数据，读取时请写NULL
/// @param length 数据长度
/// @param SRAM_CMD 传输命令
/// @return 0失败  1成功
uint8_t SRAM_DmaTransfer(uint32_t addr, uint8_t * writeData, uint16_t length, uint8_t SRAM_CMD){
    uint8_t os_err = 0;

    SRAM_CS_LOW();
    SRAM_DmaTX_Buff[0] = SRAM_CMD;
    SRAM_DmaTX_Buff[1] = (addr >> 16) & 0xff;
    SRAM_DmaTX_Buff[2] = (addr >> 8) & 0xff;
    SRAM_DmaTX_Buff[3] = (addr) & 0xff;
    if(writeData == NULL)
        memset(&SRAM_DmaTX_Buff[4], 0xff, length);
    else
        memcpy(&SRAM_DmaTX_Buff[4], writeData, length);
    //DMA配置
    SRAM_DMA_Tx_Channel->TXNUM = 4 + length;
    SRAM_DMA_Rx_Channel->TXNUM = 4 + length;
    //开启DMA传输
    DMA_EnableChannel(SRAM_DMA_Tx_Channel, ENABLE);
    DMA_EnableChannel(SRAM_DMA_Rx_Channel, ENABLE);
    //等待发送完成(2秒超时)
    OSSemPend((OS_EVENT *)App_Sem_SRAMRC,400,&os_err); 
    if(os_err == OS_ERR_TIMEOUT){
        SRAM_CS_HIGH();
        return DEF_FALSE;
    }
    SRAM_CS_HIGH();
    return DEF_TRUE;
}

/// @brief 往SRAM写入数据
/// @param addr 数据地址
/// @param writeData 数据内容
/// @param length 数据长度
/// @return 0失败  1成功
uint8_t SRAM_WriteData(uint32_t addr, uint8_t * writeData, uint16_t length){
    uint16_t i = 0;
    uint16_t writeLength = 0;
    uint16_t tempLength = length;
    // 由于干扰导致异常读写数据前初始化
    SRAM_DmaInit();
    //判断地址范围
    if((addr + length) > SRAM_ADDR_SIZE_MAX)
        return DEF_FALSE;
    //数据分段写入
    for(i = 0; i < length; i += writeLength){
        /* 数据长度设定 */
        if(tempLength <= (SRAM_DMA_BUFF_SIZE - 4))
            writeLength = tempLength;
        else
            writeLength = SRAM_DMA_BUFF_SIZE - 4;
        /* 数据写入 */
        if(SRAM_DmaTransfer(addr + i, writeData + i, writeLength, SRAMCMD_WRITE) == DEF_FALSE)
            return DEF_FALSE;
        tempLength -= writeLength;
    }
    return DEF_TRUE;
}

/// @brief 从SRAM读取数据
/// @param addr 数据地址
/// @param readData 数据内容
/// @param length 数据长度
/// @return 0失败  1成功
uint8_t SRAM_ReadData(uint32_t addr, uint8_t * readData, uint16_t length){
    uint16_t i = 0;
    uint16_t readLength = 0;
    uint16_t tempLength = length;
    
    // 由于干扰导致异常读写数据前初始化
    SRAM_DmaInit();
    //判断地址范围
    if((addr + length) > SRAM_ADDR_SIZE_MAX)
        return 0;
    //数据分段读取
    for(i = 0; i < length; i += readLength){
        /* 数据长度设定 */
        if(tempLength <= (SRAM_DMA_BUFF_SIZE - 4))
            readLength = tempLength;
        else
            readLength = SRAM_DMA_BUFF_SIZE - 4;
        /* 数据读取 */
        SRAM_DmaTransfer(addr + i, NULL, readLength, SRAMCMD_READ);
        //将DMA接收缓冲的数据写入用户缓冲
        memcpy(readData + i, &SRAM_DmaRX_Buff[4], readLength);
        tempLength -= readLength;
    }
    return 1;
}

/// @brief DMA接收中断处理函数
/// @param  none
void SRAM_DMA_Rx_Function(void){
    OS_CPU_SR cpu_sr;
    OS_ENTER_CRITICAL(); /* Tell uC/OS-II that we are starting an ISR 		 */
    OSIntEnter();

    //关闭DMA
    DMA_EnableChannel(SRAM_DMA_Rx_Channel, DISABLE);
    DMA_EnableChannel(SRAM_DMA_Tx_Channel, DISABLE);
    //清除中断标志
    DMA_ClearFlag(SRAM_DMA_Rx_FLAG, DMA1);
    //释放信号量
    OSSemPost((OS_EVENT *)App_Sem_SRAMRC);

    OSIntExit(); /* Tell uC/OS-II that we are leaving the ISR 		 */
    OS_EXIT_CRITICAL();
}
